package by.yativem.commons.task;

import java.io.Serializable;

import org.apache.log4j.Logger;

public abstract class AbstractCallableTaskCommand<ResultType, Task extends AbstractManagedTask>
		implements Serializable {
	private static final long serialVersionUID = 1L;
	private static final Logger log = Logger
			.getLogger(AbstractCallableTaskCommand.class);

	protected Task task;
	private ResultType result;
//	private final Object locker = new Object();
	protected boolean isCallCalled = false;
	private Exception exception;

	public Task getTask() {
		return task;
	}

	public final void setTask(Task task) {
		this.task = task;
	}

	protected abstract ResultType doCommand() throws Exception;

	public final ResultType call(Task task) throws Exception {
		this.task = task;	
		if (task == null) {
			throw new IllegalStateException(
					"The task should be set before the call() method will be called");
		}		
		task.putCallableCommand((AbstractCallableTaskCommand<ResultType, AbstractManagedTask>) this);

		
		if (exception != null) {
			throw exception;
		}
		return result;
	}

	protected final void executeInternal() throws Exception {
		try {
			 setResult( doCommand() );
		} catch (Exception e) {
			exception = e;
			log.error("", e);
		} finally {
			synchronized (this) {
				this.notifyAll();
			}
			
		}
	}

	protected synchronized boolean isCalled() {
		return isCallCalled;
	}

	private synchronized void setCalled() {
		isCallCalled = true;
	}

	protected final void notifyAllLockedThreads() {
		synchronized (this) {
			this.notifyAll();
		}

	}

	protected synchronized final ResultType getResult() {
		return result;
	}

	protected synchronized final void setResult(ResultType result) {
		this.result = result;
	}
	
	
	
/*
	public static AbstractCallableTaskCommand<String, AbstractManagedTask> getCancelTaskCommand() {
		return new AbstractCallableTaskCommand<String, AbstractManagedTask>() {

			@Override
			protected String doCommand() throws Exception {
				throw new AbstractManagedTask.TaskCanceledException("");
			}
		};
	}

	public static AbstractCallableTaskCommand<String, AbstractManagedTask> getPausedTaskCommand() {
		return new AbstractCallableTaskCommand<String, AbstractManagedTask>() {

			@Override
			protected String doCommand() throws Exception {
				result = "Task paused";
			
				synchronized (task.locker) {
					task.locker.wait();
				}
				
				return null;
			}
		};
	}

	protected static final class ContinueTaskCommand extends
			AbstractCallableTaskCommand<String, AbstractManagedTask> {

		@Override
		protected String doCommand() throws Exception {
			result = "Task continue";
			task.setTaskStatus(TaskStatus.RUNNING);
			return null;
		}
	};

	public static AbstractCallableTaskCommand<String, AbstractManagedTask> getContinueTaskCommand() {
		return new ContinueTaskCommand();
	}
	*/
}
